﻿using Microsoft.IdentityModel.JsonWebTokens;

namespace Digitalmes.WebApi.Infrastructure.Jwt;

public static class IJwtAuthManagerExtensions
{
    /// <summary>
    /// 生成 access_token。
    /// </summary>
    /// <param name="manager"></param>
    /// <param name="jwtToken">token 对象</param>
    /// <param name="now"></param>
    /// <param name="expires">过期时长</param>
    /// <returns></returns>
    public static string GenerateToken(this IJwtAuthManager manager, JwtToken jwtToken, DateTime now, TimeSpan expires)
    {
        List<Claim> claims = [
            new Claim (JwtRegisteredClaimNames.Sub, jwtToken.UserId.ToString()), // 同 ClaimTypes.NameIdentifier
            new Claim (JwtRegisteredClaimNames.UniqueName, jwtToken.Username), // 同 ClaimTypes.Name
            new Claim (nameof(JwtToken.TenantId), jwtToken.TenantId.ToString()),
            new Claim (JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
        ];

        foreach (var role in jwtToken.Roles)
        {
            claims.Add(new Claim(ClaimTypes.Role, role));
        }

        return manager.GenerateToken([.. claims], now, expires);
    }

    /// <summary>
    /// 从 access_token 中提取 token 对象值。
    /// </summary>
    /// <param name="manager"></param>
    /// <param name="token"></param>
    /// <returns></returns>
    public static JwtToken GetPayload(this IJwtAuthManager manager, string token)
    {
        (ClaimsPrincipal claimsPrincipal, _) = manager.DecodeJwtToken(token);
        
        var userId = claimsPrincipal.Claims.Single(s => s.Type == JwtRegisteredClaimNames.Sub).Value;
        var userName = claimsPrincipal.Claims.Single(s => s.Type == JwtRegisteredClaimNames.UniqueName).Value;
        var roles = claimsPrincipal.Claims.Where(s => s.Type == ClaimTypes.Role).Select(s => s.Value).ToArray();
        var tenantId = claimsPrincipal.Claims.Single(s => s.Type == nameof(JwtToken.TenantId)).Value;

        return new JwtToken()
        {
            UserId = Convert.ToInt64(userId),
            Username = userName,
            Roles = roles,
            TenantId = Convert.ToInt64(tenantId),
        };
    }
}
